/*
 * File Controller.java 
 */
package cs.controller;

import java.io.File;
import java.util.Enumeration;
import java.util.logging.Level;
import javax.swing.DefaultListModel;
import javax.swing.event.ListDataListener;
import cs.entity.LocalUser;
import cs.entity.User;
import cs.entity.UserFile;
import cs.entity.UserTextMessage;
import cs.gui.ChatGui;
import cs.main.ChatSystem;
import cs.model.Model;
import cs.model.State;
import cs.model.State.LocalUserState;
import cs.ni.ChatNi;

/**
 * Class controller.<br> Correspond to the Model View Controller pattern.<br>
 * It is responsible for business
 * and update the views and interact with the models.<p>
 * Package  cs.controller
 * Project ChatSystemG1 - INSA 4INFOA1 - 2013/2014
 * @author Julie DUMONS & Juste OUEDRAOGO
 */
public class Controller implements GuiController, NiController {

	/**
	 * MVC pattern: model
	 */
	private Model model;

	/**
	 * Local User references
	 */
	private LocalUser localUser;

	/**
	 * Constructor of controller
	 * @param model 
	 * @param gui
	 * @param ni
	 */
	public Controller(Model model, ChatGui gui, ChatNi ni){
		this.model = model;
		// linking the Observer/Observable relation

		// state
		model.getState().addObserver(gui); 
		model.getState().addObserver(ni); 

		//userList
		gui.getMainFrame().getList().setModel(model.getUserListModel());
		model.getUserListModel().addListDataListener((ListDataListener) gui);

		//Received Text Msg 
		model.getReceivedMsgModel().addObserver(gui);

		//text msg to send
		model.getMsgToSendModel().addObserver(ni);

		// file to send
		model.getFileToSendModel().addObserver(ni);
		model.getFileToSendModel().addObserver(gui);
		model.getReceivedFileModel().addObserver(gui); 
		model.getReceivedFileModel().addObserver(ni);


	}

	/**
	 * update the userList 
	 * add new user to the userList
	 * @param userAddr the user Ip address
	 * @param username the username
	 */
	@Override
	public void performAddUser(User user) {	
		model.getUserListModel().addElement(user);
		ChatSystem.logger.log(Level.INFO, user+" arrived\n");
	}

	/**
	 * update the userList 
	 * remove user from the userList
	 * @param user the user who will be removed from the list
	 * @param addr
	 */
	@Override
	public void performRemoveUser(User user) {
		Enumeration e = model.getUserListModel().elements();
		while(e.hasMoreElements()){
			Object obj = e.nextElement();
			User u =(User) obj;
			if(u.getIpAddress().equals(user.getIpAddress()) ){
				model.getUserListModel().removeElement(obj);
				ChatSystem.logger.log(Level.INFO, user+" lost\n");
			}
		}
	}


	/**
	 * submit connection request
	 * (called by the GUI)
	 * broadcast a hello messages to all the network interfaces
	 */
	@Override
	public void performConnect(String username) {
		//create the local user at each session
		localUser = new LocalUser(username);
		// Change the state of LocalUser
		model.getState().setcurrentState(LocalUserState.ONLINE); 
		System.out.println("You are now ONLINE");
		ChatSystem.logger.log(Level.INFO, "New connection: Local user : "+localUser.getUsername()+", IP addresses "+localUser.getIpAddrList()+"\n");
	}


	/**
	 * Called when the user wants to disconnect
	 */
	public void performDisconnect() {
		model.getState().setcurrentState(LocalUserState.OFFLINE); 
		//empty the userList
		model.getUserListModel().removeAllElements();
		System.out.println("You are now OFFLINE");
		ChatSystem.logger.log(Level.INFO, "disconnection of "+localUser.getUsername()+"\n");
	}

	/**
	 * get the current local user
	 * @return the localUser
	 */
	public LocalUser getLocalUser(){
		return localUser;
	}
	/**
	 * add a new message to the receiving queue
	 */
	@Override
	public void performAddReceivedMsg(UserTextMessage msg) {
		model.getReceivedMsgModel().addReceivedMsg(msg);
		ChatSystem.logger.log(Level.INFO, "Message received from "+msg.getRemoteUser()+"\n");

	}
	/**
	 * submit a text message sending request
	 * add a new message to the sending queue
	 */
	@Override
	public void performAddSendMsg(UserTextMessage msg) {
		model.getMsgToSendModel().addMsgToSend(msg);
		ChatSystem.logger.log(Level.INFO, "Message sent to "+msg.getRemoteUser()+"\n");
	}
	/**
	 * add a new file to the received file manager
	 */
	@Override
	public void performAddReceivedFile(UserFile uf) {		
		model.getReceivedFileModel().addReceivedFile(uf); 
		ChatSystem.logger.log(Level.INFO, "file received from "+uf.getRemoteUser()+" state = "+uf.getState()+"\n");
	}

	/**
	 * submit a file sending request
	 */
	@Override
	public void performAddSendFile(UserFile u) {
		model.getFileToSendModel().addFileToSend(u); 
		System.out.println("file to send added");
		ChatSystem.logger.log(Level.INFO, "file sent to "+u.getRemoteUser()+" state = "+u.getState()+"\n");
	}

	/**
	 * get the last received message
	 */
	@Override
	public UserTextMessage getReceivedMsg() {
		return model.getReceivedMsgModel().getRemoveReceivedMsg();
	}

	/**
	 * get the message to be sent
	 * @return the message to be sent
	 */
	@Override
	public UserTextMessage getMessageToSend() {
		return model.getMsgToSendModel().getRemoveMsgToSend();
	}

	/**
	 * get the connected users list
	 * @return the connected users list
	 */
	public DefaultListModel getListUser() {
		return model.getUserListModel();

	}
	/**
	 * action to do when upload completed
	 * remove the file sent from the sending list
	 */
	@Override
	public void performUploadComplete(UserFile file) {
		model.getFileToSendModel().setFileState(file, file.getState());
		model.getFileToSendModel().removeFile(file);
		ChatSystem.logger.log(Level.INFO, "file sent "+file.getRemoteUser()+" state : "+file.getState()+"\n");
	}

	/**
	 * action to do when the download completed
	 * remove the received file from the received list
	 */
	@Override
	public void performDownloadComplete(UserFile file) {
		UserFile fichier = model.getReceivedFileModel().setFileState(file, file.getState());
		ChatSystem.logger.log(Level.INFO, "file received from "+file.getRemoteUser()+" state "+file.getState()+"\n");
		if(file.getState() == UserFile.State.COMPLETED){
			//check whether the file is present in the authorized download (if request received before)
			if(fichier!=null){
				File downloaded = file.getFile();
				downloaded.renameTo(fichier.getFile());
			}
			else{
				file.getFile().delete();
				ChatSystem.logger.log(Level.WARNING, "file download not authorized");
			}
		}
		model.getReceivedFileModel().removeFile(file);

	}

	/**
	 * action to do when receiving a response to a file request
	 */
	@Override
	public void performReceivedFileAnwser(UserFile file) {
		model.getFileToSendModel().setFileState(file, file.getState());

	}
	/**
	 * action to do when receiving a file request
	 */
	@Override
	public void performReceivedFileRequest(UserFile file) {
		//add a file to the receiving queue
		performAddReceivedFile(file);

	}

	/**
	 * action to do when the local user accept a file download
	 */
	@Override
	public void performFileAccepted(UserFile u) {
		System.out.println("file accepted");
		model.getReceivedFileModel().setFileState(u, UserFile.State.ACCEPTED);

	}
	/**
	 * action to do when the local user reject a file download
	 */
	@Override
	public void performFileRefused(UserFile u) {
		System.out.println("file refused");
		model.getReceivedFileModel().setFileState(u, UserFile.State.REFUSED);

	}

	/**
	 * get the file to send
	 * @return the file choosed by the local user 
	 */
	@Override
	public UserFile getFileTosend(UserFile file) {
		return model.getFileToSendModel().getFile(file);

	}

	/**
	 * report network errors
	 */
	@Override
	public void performNetworkError() {
		model.getState().setcurrentState(State.LocalUserState.ERROR);
		ChatSystem.logger.log(Level.SEVERE, "Network error\n");

	}
}